package compilers.stmt;

import java.io.BufferedWriter;
import java.io.IOException;

import compilers.condition.Factor;
import compilers.condition.Term;
import compilers.node.Stmt;
import compilers.table.MemScope;
import compilers.types.IntType;
import compilers.types.Type;

public class If extends Stmt {
	Condition fExpr;
	private Stmt fStatement1;
	private Stmt fStatement2;
	
	public If(){}
	
	public If(Condition fExpr, Stmt fStatement1, Stmt fStatement2) {
		super();
		this.fExpr = fExpr;
		this.setfStatement1(fStatement1);
		this.setfStatement2(fStatement2);
	}
	
	public If(Condition fExpr, Stmt fStatement1) {
		super();
		this.fExpr = fExpr;
		this.setfStatement1(fStatement1);
	}
	
	public void setElse(Stmt fStatement2) {
		this.setfStatement2(fStatement2);
	}

	@Override
	public void print(int tab) {
		for (int i=1;i<=tab;i++){System.out.print("\t");}System.out.print("|-");
			System.out.println("If");
			fExpr.print(tab+1);
			getfStatement1().print(tab+1);
			if (getfStatement2() != null) {
				getfStatement2().print(tab+1);
			}
	}

	public void generate(BufferedWriter writer, MemScope scope) throws IOException {
		// optimalisation
		if (fExpr instanceof Term) {
			Term t = (Term)fExpr;
			Type tmp = t.compute();
			if (tmp != null) {
				MemScope myScope = new MemScope(scope);
				if (tmp.getfValue() > 0) {
					// expr is always true
					fStatement1.generate(writer, myScope);
				} else {
					// expr is always false
					if (fStatement2 != null) {
						fStatement2.generate(writer, myScope);
					}
				}
			} else {
				generateWithoutOptimalisation(writer, scope);
			}
		}
	}
	
	public void generateWithoutOptimalisation(BufferedWriter writer, MemScope scope) throws IOException {
		MemScope myScope = new MemScope(scope);

		fExpr.setfRes(new IntType(true));
		
		String lbl1 = myScope.getUniqueLabel();
		String lbl2 = myScope.getUniqueLabel();
		
		fExpr.generate(writer, myScope);
		if(fExpr.getClass().equals(Factor.class) || fExpr instanceof Type) {
			writer.write("conv i b\n");
		}
		if (fStatement2 != null) {
			writer.write("fjp cond_" + lbl1 + "\n");
		} else {
			writer.write("fjp cond_" + lbl2 + "\n");
		}
		fStatement1.generate(writer, myScope);
		writer.write("ujp cond_" + lbl2 + "\n");
		if (fStatement2 != null) {
			writer.write("cond_" + lbl1 + ":\n");
			fStatement2.generate(writer, myScope);
		}
		writer.write("cond_" + lbl2 + ":\n");
	}

	public Stmt getfStatement2() {
		return fStatement2;
	}

	public void setfStatement2(Stmt fStatement2) {
		this.fStatement2 = fStatement2;
	}

	public Stmt getfStatement1() {
		return fStatement1;
	}

	public void setfStatement1(Stmt fStatement1) {
		this.fStatement1 = fStatement1;
	}

}
